/******/
(function(modules) { // webpackBootstrap
    /******/ // The module cache
    /******/
    var installedModules = {};

    /******/ // The require function
    /******/
    function __webpack_require__(moduleId) {

        /******/ // Check if module is in cache
        /******/
        if (installedModules[moduleId])
        /******/
            return installedModules[moduleId].exports;

        /******/ // Create a new module (and put it into the cache)
        /******/
        var module = installedModules[moduleId] = {
            /******/
            exports: {},
            /******/
            id: moduleId,
            /******/
            loaded: false
                /******/
        };

        /******/ // Execute the module function
        /******/
        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

        /******/ // Flag the module as loaded
        /******/
        module.loaded = true;

        /******/ // Return the exports of the module
        /******/
        return module.exports;
        /******/
    }


    /******/ // expose the modules object (__webpack_modules__)
    /******/
    __webpack_require__.m = modules;

    /******/ // expose the module cache
    /******/
    __webpack_require__.c = installedModules;

    /******/ // __webpack_public_path__
    /******/
    __webpack_require__.p = "";

    /******/ // Load entry module and return exports
    /******/
    return __webpack_require__(0);
    /******/
})
/************************************************************************/
/******/
([
    /* 0 */
    /***/
    function(module, exports, __webpack_require__) {

        /*
         * 
         * version 1.0
         * built in 2015.11.19
         */

        var mmHistory = __webpack_require__(6)
        var storage = __webpack_require__(7)

        function Router() {
            this.rules = []
        }


        var placeholder = /([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g
        Router.prototype = storage
        avalon.mix(storage, {
            error: function(callback) {
                this.errorback = callback
            },
            _pathToRegExp: function(pattern, opts) {
                var keys = opts.keys = [],
                    //      segments = opts.segments = [],
                    compiled = '^',
                    last = 0,
                    m, name, regexp, segment;

                while ((m = placeholder.exec(pattern))) {
                    name = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null
                    regexp = m[4] || (m[1] == '*' ? '.*' : 'string')
                    segment = pattern.substring(last, m.index);
                    var type = this.$types[regexp]
                    var key = {
                        name: name
                    }
                    if (type) {
                        regexp = type.pattern
                        key.decode = type.decode
                    }
                    keys.push(key)
                    compiled += quoteRegExp(segment, regexp, false)
                        //  segments.push(segment)
                    last = placeholder.lastIndex
                }
                segment = pattern.substring(last);
                compiled += quoteRegExp(segment) + (opts.strict ? opts.last : "\/?") + '$';
                var sensitive = typeof opts.caseInsensitive === "boolean" ? opts.caseInsensitive : true
                    //  segments.push(segment);
                opts.regexp = new RegExp(compiled, sensitive ? 'i' : undefined);
                return opts

            },
            //添加一个路由规则
            add: function(path, callback, opts) {
                var array = this.rules
                if (path.charAt(0) !== "/") {
                    avalon.error("avalon.router.add的第一个参数必须以/开头")
                }
                opts = opts || {}
                opts.callback = callback
                if (path.length > 2 && path.charAt(path.length - 1) === "/") {
                    path = path.slice(0, -1)
                    opts.last = "/"
                }
                avalon.Array.ensure(array, this._pathToRegExp(path, opts))
            },
            //判定当前URL与已有状态对象的路由规则是否符合
            route: function(path, query) {
                path = path.trim()
                var rules = this.rules
                for (var i = 0, el; el = rules[i++];) {
                    var args = path.match(el.regexp)
                    if (args) {
                        el.query = query || {}
                        el.path = path
                        el.params = {}
                        var keys = el.keys
                        args.shift()
                        if (keys.length) {
                            this._parseArgs(args, el)
                        }
                        return el.callback.apply(el, args)
                    }
                }
                if (this.errorback) {
                    this.errorback()
                }
            },
            _parseArgs: function(match, stateObj) {
                var keys = stateObj.keys
                for (var j = 0, jn = keys.length; j < jn; j++) {
                    var key = keys[j]
                    var value = match[j] || ''
                    if (typeof key.decode === 'function') { //在这里尝试转换参数的类型
                        var val = key.decode(value)
                    } else {
                        try {
                            val = JSON.parse(value)
                        } catch (e) {
                            val = value
                        }
                    }
                    match[j] = stateObj.params[key.name] = val
                }
            },
            /*
             *  @interface avalon.router.navigate 设置历史(改变URL)
             *  @param hash 访问的url hash   
             */
            navigate: function(hash, mode) {
                var parsed = parseQuery(hash)
                var newHash = this.route(parsed.path, parsed.query)
                if (isLegalPath(newHash)) {
                    hash = newHash
                }
                //保存到本地储存或cookie
                avalon.router.setLastPath(hash)
                    // 模式0, 不改变URL, 不产生历史实体, 执行回调
                    // 模式1, 改变URL, 不产生历史实体,   执行回调
                    // 模式2, 改变URL, 产生历史实体,    执行回调
                if (mode === 1) {

                    avalon.history.setHash(hash, true)
                } else if (mode === 2) {
                    avalon.history.setHash(hash)
                }
                return hash
            },
            /*
             *  @interface avalon.router.when 配置重定向规则
             *  @param path 被重定向的表达式，可以是字符串或者数组
             *  @param redirect 重定向的表示式或者url
             */
            when: function(path, redirect) {
                var me = this,
                    path = path instanceof Array ? path : [path]
                avalon.each(path, function(index, p) {
                    me.add(p, function() {
                        var info = me.urlFormate(redirect, this.params, this.query)
                        me.navigate(info.path + info.query)
                    })
                })
                return this
            },
            urlFormate: function(url, params, query) {
                var query = query ? queryToString(query) : "",
                    hash = url.replace(placeholder, function(mat) {
                        var key = mat.replace(/[\{\}]/g, '').split(":")
                        key = key[0] ? key[0] : key[1]
                        return params[key] !== undefined ? params[key] : ''
                    }).replace(/^\//g, '')
                return {
                    path: hash,
                    query: query
                }
            },
            /* *
             `'/hello/'` - 匹配'/hello/'或'/hello'
             `'/user/:id'` - 匹配 '/user/bob' 或 '/user/1234!!!' 或 '/user/' 但不匹配 '/user' 与 '/user/bob/details'
             `'/user/{id}'` - 同上
             `'/user/{id:[^/]*}'` - 同上
             `'/user/{id:[0-9a-fA-F]{1,8}}'` - 要求ID匹配/[0-9a-fA-F]{1,8}/这个子正则
             `'/files/{path:.*}'` - Matches any URL starting with '/files/' and captures the rest of the
             path into the parameter 'path'.
             `'/files/*path'` - ditto.
             */
            // avalon.router.get("/ddd/:dddID/",callback)
            // avalon.router.get("/ddd/{dddID}/",callback)
            // avalon.router.get("/ddd/{dddID:[0-9]{4}}/",callback)
            // avalon.router.get("/ddd/{dddID:int}/",callback)
            // 我们甚至可以在这里添加新的类型，avalon.router.$type.d4 = { pattern: '[0-9]{4}', decode: Number}
            // avalon.router.get("/ddd/{dddID:d4}/",callback)
            $types: {
                date: {
                    pattern: "[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])",
                    decode: function(val) {
                        return new Date(val.replace(/\-/g, "/"))
                    }
                },
                string: {
                    pattern: "[^\\/]*",
                    decode: function(val) {
                        return val;
                    }
                },
                bool: {
                    decode: function(val) {
                        return parseInt(val, 10) === 0 ? false : true;
                    },
                    pattern: "0|1"
                },
                'int': {
                    decode: function(val) {
                        return parseInt(val, 10);
                    },
                    pattern: "\\d+"
                }
            }
        })


        module.exports = avalon.router = new Router


        function parseQuery(url) {
            var array = url.split("?"),
                query = {},
                path = array[0],
                querystring = array[1]
            if (querystring) {
                var seg = querystring.split("&"),
                    len = seg.length,
                    i = 0,
                    s;
                for (; i < len; i++) {
                    if (!seg[i]) {
                        continue
                    }
                    s = seg[i].split("=")
                    query[decodeURIComponent(s[0])] = decodeURIComponent(s[1])
                }
            }
            return {
                path: path,
                query: query
            }
        }

        function isLegalPath(path) {
            if (path === '/')
                return true
            if (typeof path === 'string' && path.length > 1 && path.charAt(0) === '/') {
                return true
            }
        }

        function queryToString(obj) {
            if (typeof obj === 'string')
                return obj
            var str = []
            for (var i in obj) {
                if (i === "query")
                    continue
                str.push(i + '=' + encodeURIComponent(obj[i]))
            }
            return str.length ? '?' + str.join("&") : ''
        }


        function quoteRegExp(string, pattern, isOptional) {
            var result = string.replace(/[\\\[\]\^$*+?.()|{}]/g, "\\$&");
            if (!pattern)
                return result;
            var flag = isOptional ? '?' : '';
            return result + flag + '(' + pattern + ')' + flag;
        }


        /***/
    },
    /* 1 */
    ,
    /* 2 */
    ,
    /* 3 */
    ,
    /* 4 */
    ,
    /* 5 */
    ,
    /* 6 */
    /***/
    function(module, exports) {

        /*!
         * mmHistory
         * 用于监听地址栏的变化
         * https://github.com/flatiron/director/blob/master/lib/director/browser.js
         * https://github.com/visionmedia/page.js/blob/master/page.js
         */

        var location = document.location
        var oldIE = avalon.msie <= 7
        var supportPushState = !!(window.history.pushState)
        var supportHashChange = !!("onhashchange" in window && (!window.VBArray || !oldIE))
        var defaults = {
            root: "/",
            html5: false,
            hashPrefix: "!",
            iframeID: null, //IE6-7，如果有在页面写死了一个iframe，这样似乎刷新的时候不会丢掉之前的历史
            interval: 50, //IE6-7,使用轮询，这是其时间时隔,
            autoScroll: false
        }
        var mmHistory = {
            hash: getHash(location.href),
            check: function() {
                var h = getHash(location.href)
                if (h !== this.hash) {
                    this.hash = h
                    this.onHashChanged()
                }
            },
            start: function(options) {
                if (this.started)
                    throw new Error('avalon.history has already been started')
                this.started = true
                    //监听模式
                if (typeof options === 'boolean') {
                    options = {
                        html5: options
                    }
                }

                options = avalon.mix({}, defaults, options || {})
                if (options.fireAnchor) {
                    options.autoScroll = true
                }
                var rootPath = options.root
                if (!/^\//.test(rootPath)) {
                    avalon.error('root配置项必须以/字符开始, 以非/字符结束')
                }
                if (rootPath.length > 1) {
                    options.root = rootPath.replace(/\/$/, '')
                }
                var html5Mode = options.html5
                this.options = options
                this.mode = html5Mode ? "popstate" : "hashchange"
                if (!supportPushState) {
                    if (html5Mode) {
                        avalon.warn("浏览器不支持HTML5 pushState，平稳退化到onhashchange!")
                    }
                    this.mode = "hashchange"
                }
                if (!supportHashChange) {
                    this.mode = "iframepoll"
                }
                avalon.log('avalon run mmHistory in the ', this.mode, 'mode')
                    // 支持popstate 就监听popstate
                    // 支持hashchange 就监听hashchange(IE8,IE9,FF3)
                    // 否则的话只能每隔一段时间进行检测了(IE6, IE7)
                switch (this.mode) {
                    case "popstate":
                        // At least for now HTML5 history is available for 'modern' browsers only
                        // There is an old bug in Chrome that causes onpopstate to fire even
                        // upon initial page load. Since the handler is run manually in init(),
                        // this would cause Chrome to run it twise. Currently the only
                        // workaround seems to be to set the handler after the initial page load
                        // http://code.google.com/p/chromium/issues/detail?id=63040
                        setTimeout(function() {
                            window.onpopstate = mmHistory.onHashChanged
                        }, 500)
                        break
                    case "hashchange":
                        window.onhashchange = mmHistory.onHashChanged
                        break
                    case "iframepoll":
                        //也有人这样玩 http://www.cnblogs.com/meteoric_cry/archive/2011/01/11/1933164.html
                        avalon.ready(function() {
                            var iframe = document.createElement('iframe')
                            iframe.id = options.iframeID
                            iframe.style.display = 'none'
                            document.body.appendChild(iframe)
                            mmHistory.iframe = iframe
                            mmHistory.writeFrame('')
                            if (avalon.msie) {
                                function onPropertyChange() {
                                    if (event.propertyName === 'location') {
                                        mmHistory.check()
                                    }
                                }
                                document.attachEvent('onpropertychange', onPropertyChange)
                                mmHistory.onPropertyChange = onPropertyChange
                            }

                            mmHistory.intervalID = window.setInterval(function() {
                                mmHistory.check()
                            }, options.interval)

                        })
                        break
                }
                //页面加载时触发onHashChanged
                this.onHashChanged()
            },
            stop: function() {
                switch (this.mode) {
                    case "popstate":
                        window.onpopstate = avalon.noop
                        break
                    case "hashchange":
                        window.onhashchange = avalon.noop
                        break
                    case "iframepoll":
                        if (this.iframe) {
                            document.body.removeChild(this.iframe)
                            this.iframe = null
                        }
                        if (this.onPropertyChange) {
                            document.detachEvent('onpropertychange', this.onPropertyChange)
                        }
                        clearInterval(this.intervalID)
                        break
                }
                this.started = false
            },
            setHash: function(s, replace) {
                switch (this.mode) {
                    case 'iframepoll':
                        if (replace) {
                            var iframe = this.iframe
                            if (iframe) {
                                //contentWindow 兼容各个浏览器，可取得子窗口的 window 对象。
                                //contentDocument Firefox 支持，> ie8 的ie支持。可取得子窗口的 document 对象。
                                iframe.contentWindow._hash = s
                            }
                        } else {
                            this.writeFrame(s)
                        }
                        break
                    case 'popstate':
                        var path = (this.options.root + '/' + s).replace(/\/+/g, '/')
                        var method = replace ? 'replaceState' : 'pushState'
                        history[method]({}, document.title, path)
                            // 手动触发onpopstate event
                        this.onHashChanged()
                        break
                    default:
                        //http://stackoverflow.com/questions/9235304/how-to-replace-the-location-hash-and-only-keep-the-last-history-entry
                        var newHash = this.options.hashPrefix + s
                        if (replace && location.hash !== newHash) {
                            history.back()
                        }
                        location.hash = newHash
                        break
                }
            },
            writeFrame: function(s) {
                // IE support...
                var f = mmHistory.iframe
                var d = f.contentDocument || f.contentWindow.document
                d.open()
                d.write("<script>_hash = '" + s + "'; onload = parent.avalon.history.syncHash;<script>")
                d.close()
            },
            syncHash: function() {
                // IE support...
                var s = this._hash
                if (s !== getHash(location.href)) {
                    location.hash = s
                }
                return this
            },
            getPath: function() {
                var path = location.pathname
                var path = path.split(this.options.root)[1]
                if (path.charAt(0) !== '/') {
                    path = '/' + path
                }
                return path
            },
            onHashChanged: function(hash, clickMode) {
                if (!clickMode) {
                    hash = mmHistory.mode === 'popstate' ? mmHistory.getPath() :
                        location.href.replace(/.*#!?/, '')
                }
                hash = decodeURIComponent(hash)
                hash = hash.charAt(0) === '/' ? hash : '/' + hash
                if (hash !== mmHistory.hash) {
                    mmHistory.hash = hash

                    if (avalon.router) { //即mmRouter
                        hash = avalon.router.navigate(hash, 0)
                    }

                    if (clickMode) {
                        mmHistory.setHash(hash)
                    }
                    if (clickMode && mmHistory.options.autoScroll) {
                        autoScroll(hash.slice(1))
                    }
                }

            }
        }

        function getHash(path) {
            // IE6直接用location.hash取hash，可能会取少一部分内容
            // 比如 http://www.cnblogs.com/rubylouvre#stream/xxxxx?lang=zh_c
            // ie6 => location.hash = #stream/xxxxx
            // 其他浏览器 => location.hash = #stream/xxxxx?lang=zh_c
            // firefox 会自作多情对hash进行decodeURIComponent
            // 又比如 http://www.cnblogs.com/rubylouvre/#!/home/q={%22thedate%22:%2220121010~20121010%22}
            // firefox 15 => #!/home/q={"thedate":"20121010~20121010"}
            // 其他浏览器 => #!/home/q={%22thedate%22:%2220121010~20121010%22}
            var index = path.indexOf("#")
            if (index === -1) {
                return ''
            }
            return decodeURI(path.slice(index))
        }



        //劫持页面上所有点击事件，如果事件源来自链接或其内部，
        //并且它不会跳出本页，并且以"#/"或"#!/"开头，那么触发updateLocation方法
        avalon.bind(document, "click", function(e) {
            //https://github.com/asual/jquery-address/blob/master/src/jquery.address.js
            //https://github.com/angular/angular.js/blob/master/src/ng/location.js
            //下面十种情况将阻止进入路由系列
            //1. 路由器没有启动
            if (!mmHistory.started) {
                return
            }
            //2. 不是左键点击或使用组合键
            if (e.ctrlKey || e.metaKey || e.shiftKey || e.which === 2 || e.button === 2) {
                return
            }
            //3. 此事件已经被阻止
            if (e.returnValue === false) {
                return
            }
            //4. 目标元素不A标签,或不在A标签之内
            var el = e.path ? e.path[0] : e.target || e.srcElement || {}
            while (el.nodeName !== "A") {
                el = el.parentNode
                if (!el || el.tagName === "BODY") {
                    return
                }
            }
            //5. 没有定义href属性或在hash模式下,只有一个#
            //IE6/7直接用getAttribute返回完整路径
            var href = el.getAttribute('href', 2) || el.getAttribute("xlink:href") || ''
            if (href.slice(0, 2) !== '#!') {
                return
            }

            //6. 目标链接是用于下载资源或指向外部
            if (el.getAttribute('download') || el.getAttribute('rel') === 'external')
                return

            //7. 只是邮箱地址
            if (href.indexOf('mailto:') > -1) {
                return
            }
            //8. 目标链接要新开窗口
            if (el.target && el.target !== '_self') {
                return
            }

            e.preventDefault()
                //终于达到目的地
            mmHistory.onHashChanged(href.replace('#!', ''), true)

        })

        //得到页面第一个符合条件的A标签
        function getFirstAnchor(name) {
            var list = document.getElementsByTagName('A')
            for (var i = 0, el; el = list[i++];) {
                if (el.name === name) {
                    return el
                }
            }
        }

        function getOffset(elem) {
            var position = avalon(elem).css('position'),
                offset
            if (position !== 'fixed') {
                offset = 0
            } else {
                offset = elem.getBoundingClientRect().bottom
            }

            return offset
        }

        function autoScroll(hash) {
            //取得页面拥有相同ID的元素
            var elem = document.getElementById(hash)
            if (!elem) {
                //取得页面拥有相同name的A元素
                elem = getFirstAnchor(hash)
            }
            if (elem) {
                elem.scrollIntoView()
                var offset = getOffset(elem)
                if (offset) {
                    var elemTop = elem.getBoundingClientRect().top
                    window.scrollBy(0, elemTop - offset.top)
                }
            } else {
                window.scrollTo(0, 0)
            }
        }


        module.exports = avalon.history = mmHistory


        /***/
    },
    /* 7 */
    /***/
    function(module, exports) {


        function supportLocalStorage() {
            try { //看是否支持localStorage
                localStorage.setItem("avalon", 1)
                localStorage.removeItem("avalon")
                return true
            } catch (e) {
                return false
            }
        }

        function escapeCookie(value) {
            return String(value).replace(/[,;"\\=\s%]/g, function(character) {
                return encodeURIComponent(character)
            });
        }
        var ret = {}
        if (supportLocalStorage()) {
            ret.getLastPath = function() {
                return localStorage.getItem('msLastPath')
            }
            var cookieID
            ret.setLastPath = function(path) {
                if (cookieID) {
                    clearTimeout(cookieID)
                    cookieID = null
                }
                localStorage.setItem("msLastPath", path)
                cookieID = setTimeout(function() { //模拟过期时间
                    localStorage.removItem("msLastPath")
                }, 1000 * 60 * 60 * 24)
            }
        } else {

            ret.getLastPath = function() {
                return getCookie.getItem('msLastPath')
            }
            ret.setLastPath = function(path) {
                setCookie('msLastPath', path)
            }

            function setCookie(key, value) {
                var date = new Date() //将date设置为1天以后的时间 
                date.setTime(date.getTime() + 1000 * 60 * 60 * 24)
                document.cookie = escapeCookie(key) + '=' + escapeCookie(value) + ';expires=' + date.toGMTString()
            }

            function getCookie(name) {
                var m = String(document.cookie).match(new RegExp('(?:^| )' + name + '(?:(?:=([^;]*))|;|$)')) || ["", ""]
                return decodeURIComponent(m[1])
            }
        }

        module.exports = ret

        /***/
    }
    /******/
]);